package com.uuah.server.endpoint;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.uuah.exception.lifecycle.InitialisationException;
import com.uuah.server.UuahServer;
import com.uuah.server.api.IUuahContext;
import com.uuah.server.api.endpoint.IEndpointBuilder;
import com.uuah.server.api.endpoint.IEndpointFactory;
import com.uuah.server.api.endpoint.IEndpointURI;
import com.uuah.server.api.endpoint.IUuahEndpoint;
import com.uuah.server.config.i18n.ServerMessages;
import com.uuah.server.exception.AbstractUuahServerException;
import com.uuah.server.exception.endpoint.EndpointException;
import com.uuah.server.exception.registry.RegistrationException;

/**
 *
 * TODO comment ...
 *
 * <p>
 * update record:updator，update time，update content and version
 * </p>
 *
 * @author <a href="jonny_quan@hotmail.com">jonny</a>
 * @date 2009 2009-3-27 下午01:36:54
 * @version 1.0.0
 */
public class EndpointFactory implements IEndpointFactory {
	protected transient final Logger logger = LoggerFactory
			.getLogger(EndpointFactory.class);

	public static final String ENDPOINT_REGISTRY_PREFIX = "endpoint:";

	protected IUuahContext uuahContext;

	public IUuahEndpoint getRequestEndpoint(String uri)
			throws AbstractUuahServerException {
		if (logger.isDebugEnabled()) {
			logger
					.debug("DefaultEndpointFactory request for request endpoint for uri: "
							+ uri);
		}
		IEndpointBuilder endpointBuilder = lookupEndpointBuilder(uri);
		if (endpointBuilder == null) {
			if (logger.isDebugEnabled()) {
				logger
						.debug("Named EndpointBuilder not found, creating endpoint from uri");
			}
			endpointBuilder = new EndpointURIEndpointBuilder(
					new URIBuilder(uri), uuahContext);
		}
		return getRequestEndpoint(endpointBuilder);
	}

	protected IEndpointBuilder lookupEndpointBuilder(String endpointName) {
		if (logger.isDebugEnabled()) {
			logger.debug("Looking up EndpointBuilder with name:" + endpointName
					+ " in registry");
		}
		IEndpointBuilder endpointBuilder = UuahServer.getUuahContext()
				.getRegistry().lookupEndpointBuilder(endpointName);
		if (endpointBuilder != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("EndpointBuilder with name:" + endpointName
						+ " FOUND");

			}
		}
		return endpointBuilder;
	}

	public IUuahEndpoint getRequestEndpoint(IEndpointBuilder builder)
			throws AbstractUuahServerException {
		IUuahEndpoint endpoint;
		try {
			endpoint = builder.buildRequestEndpoint();
		} catch (InitialisationException e) {
			throw new AbstractUuahServerException(e);
		}
		return (IUuahEndpoint) registerEndpoint(endpoint);
	}

	protected IUuahEndpoint registerEndpoint(IUuahEndpoint endpoint)
			throws RegistrationException {
		IUuahEndpoint registryEndpoint = (IUuahEndpoint) uuahContext.getRegistry()
				.lookupObject(ENDPOINT_REGISTRY_PREFIX + endpoint.hashCode());
		if (registryEndpoint == null) {
			uuahContext.getRegistry().registerObject(
					ENDPOINT_REGISTRY_PREFIX + endpoint.hashCode(), endpoint);
			registryEndpoint = endpoint;
		}
		return registryEndpoint;
	}

	public IEndpointBuilder getEndpointBuilder(String uri)
			throws AbstractUuahServerException {
		if (logger.isDebugEnabled()) {
			logger
					.debug("DefaultEndpointFactory request for endpoint builder for uri: "
							+ uri);
		}
		IEndpointBuilder endpointBuilder = lookupEndpointBuilder(uri);
		if (endpointBuilder != null) {
			try {
				endpointBuilder = (IEndpointBuilder) endpointBuilder.clone();
			} catch (Exception e) {
				throw new EndpointException(ServerMessages
						.failedToClone("global endpoint EndpointBuilder"), e);
			}
		} else {
			if (logger.isDebugEnabled()) {
				logger
						.debug("Named EndpointBuilder not found, creating endpoint builder for uri");
			}
			endpointBuilder = new EndpointURIEndpointBuilder(
					new URIBuilder(uri), uuahContext);
		}
		return endpointBuilder;
	}

	public void setUuahContext(IUuahContext context) {
		this.uuahContext = context;
	}

	public IUuahEndpoint getRequestEndpoint(IEndpointURI uri)
			throws AbstractUuahServerException {
		return (IUuahEndpoint) getEndpoint(uri, new EndpointSource() {
			public IUuahEndpoint getEndpoint(IEndpointBuilder builder)
					throws AbstractUuahServerException {
				return getRequestEndpoint(builder);
			}
		});
	}

	protected IUuahEndpoint getEndpoint(IEndpointURI uri, EndpointSource source)
			throws AbstractUuahServerException {
		if (logger.isDebugEnabled()) {
			logger.debug("DefaultEndpointFactory request for endpoint for: "
					+ uri);
		}
		IEndpointBuilder endpointBuilder = null;
		if (uri.getEndpointName() != null) {
			endpointBuilder = lookupEndpointBuilder(uri.getEndpointName());
			if (endpointBuilder == null) {
				throw new IllegalArgumentException("The endpoint with name: "
						+ uri.getEndpointName() + "was not found.");
			}
		} else {
			if (logger.isDebugEnabled()) {
				logger
						.debug("Named EndpointBuilder not found, creating endpoint from uri");
			}
			endpointBuilder = new EndpointURIEndpointBuilder(
					new URIBuilder(uri), uuahContext);
		}
		return source.getEndpoint(endpointBuilder);
	}

	private interface EndpointSource {
		IUuahEndpoint getEndpoint(IEndpointBuilder endpointBuilder)
				throws AbstractUuahServerException;
	}

}
